<head><meta name="viewport" content="user-scalable=no,initial-scale=1,maximum-scale=1">
<meta charset=utf-8>
<style>
body { margin: 0px; }
canvas { width:100%; height:100%; overflow: hidden; }
</style>
<script type="text/javascript" src="../h3du_min.js"></script>
<script type="text/javascript" src="../extras/evaluators.js"></script>
<script type="text/javascript" src="../extras/camera.js"></script>
<script type="text/javascript" src="../extras/frame.js"></script>
<script type="text/javascript" src="demoutil.js"></script>
<script type="text/javascript" src="../extras/meshjson.js"></script>
</head>
<body>
<div style="position:absolute;left:0;top:1em">
<div id=links></div>
<div id=settings></div>
</div>
<canvas id=canvas>
</canvas>
<script id="demo">
/* global H3DU, addLink, makeMesh, pushSettings */
// <!--
/*
 Any copyright to this file is released to the Public Domain.
 http://creativecommons.org/publicdomain/zero/1.0/
 If you like this, you should donate
 to Peter O. (original author of
 the Public Domain HTML 3D Library) at:
 http://peteroupc.github.io/
*/
/**
 * A curve evaluator object that calculates a knot in the form of the Fourier series<p>
 * <b>F</b>(u) = &Sigma;<sub>i=1, n</sub> <b>a</b> cos(<i>iu</i>) + <b>b</b> sin(<i>iu</i>).<p>
 * @param {Array<Array<Number>>} a The cosine coefficients.
 * @param {Array<Array<Number>>} b The sine coefficients.
 */
/* exported FourierKnot */
function FourierKnot(a, b) {
  "use strict";
  this.a = a; // Cosine coefficients
  this.b = b; // Sine coefficients
  this.idx = 0;
  if(this.a.length !== this.b.length) {
    throw new Error("a and b must be the same length");
  }
  this.endPoints = function() {
    return [0, H3DU.Math.PITimes2];
  };
  this.evaluate = function(u) {
    var ret = [0, 0, 0];
    var cosStep = Math.cos(u);
    var sinStep = u >= 0 && u < 6.283185307179586 ? u <= 3.141592653589793 ? Math.sqrt(1.0 - cosStep * cosStep) : -Math.sqrt(1.0 - cosStep * cosStep) : Math.sin(u);
    var c = sinStep;
    var s = cosStep;
    for(var i = 0; i < this.a.length; i++) {
      var ai = this.a[i];
      var bi = this.b[i];
      ret[0] += c * ai[0] + s * bi[0];
      ret[1] += c * ai[1] + s * bi[1];
      ret[2] += c * ai[2] + s * bi[2];
      var ts = cosStep * c + sinStep * s;
      var tc = cosStep * s - sinStep * c;
      c = ts;
      s = tc;
    }
    return ret;
  };
}

var Superellipsoid = function(xRadius, yRadius, zRadius, n, m) {
  "use strict";
  this.xRadius = xRadius;
  this.yRadius = yRadius;
  this.zRadius = zRadius;
 // exponent for the sines and cosines in U-axis
  this.n = typeof n === "undefined" || n === null ? 1 : n;
 // exponent for the sines and cosines in V-axis
  this.m = typeof m === "undefined" || m === null ? 1 : m;
  this.endPoints = function() {
    return [-Math.PI / 2, Math.PI / 2, -Math.PI, Math.PI];
  };
  this.evaluate = function(u, v) {
    var cosu = Superellipsoid.cospow(u, this.n);
    return [
      Superellipsoid.cospow(v, this.m) * cosu * this.xRadius,
      Superellipsoid.sinpow(v, this.m) * cosu * this.yRadius,
      Superellipsoid.sinpow(u, this.n) * this.zRadius
    ];
  };
};

Superellipsoid.sinpow = function(x, n) {
  "use strict";
  var r = Math.sin(x);
  return (r > 0 ? 1 : -1) * Math.pow(Math.abs(r), n);
};
Superellipsoid.cospow = function(x, n) {
  "use strict";
  var r = Math.cos(x);
  return (r > 0 ? 1 : -1) * Math.pow(Math.abs(r), n);
};

var Supertoroid = function(xRadius, yRadius, innerRadius, n, m) {
  "use strict";
  this.xRadius = xRadius;
  this.yRadius = yRadius;
  this.innerRadius = innerRadius;
 // exponent for the sines and cosines in U-axis
  this.n = typeof n === "undefined" || n === null ? 1 : n;
 // exponent for the sines and cosines in V-axis
  this.m = typeof m === "undefined" || m === null ? 1 : m;
  this.endPoints = function() {
    return [0, H3DU.Math.PiTimes2, 0, H3DU.Math.PiTimes2];
  };
  this.evaluate = function(u, v) {
    var cosu = Superellipsoid.cospow(u, this.n);
    return [
      Superellipsoid.cospow(v, this.m) * (cosu * this.innerRadius + this.xRadius),
      Superellipsoid.sinpow(v, this.m) * (cosu * this.innerRadius + this.yRadius),
      Superellipsoid.sinpow(u, this.n) * this.innerRadius
    ];
  };
};

var KleinBottle = function() {
  "use strict";
  this.endPoints = function() {
    return [0, H3DU.Math.PiTimes2, 0, H3DU.Math.PiTimes2];
  };
  this.evaluate = function(u, v) {
    var x, y, z;
    var cosu = Math.cos(u);
    var sinu = u >= 0 && u < 6.283185307179586 ? u <= 3.141592653589793 ? Math.sqrt(1.0 - cosu * cosu) : -Math.sqrt(1.0 - cosu * cosu) : Math.sin(u);
    var cosv = Math.cos(v);
    var sinv = v >= 0 && v < 6.283185307179586 ? v <= 3.141592653589793 ? Math.sqrt(1.0 - cosv * cosv) : -Math.sqrt(1.0 - cosv * cosv) : Math.sin(v);
    if(u < Math.PI) {
      x = 3 * cosu * (1 + sinu) + 2 * (1 - cosu / 2) * cosu * cosv;
      z = -8 * sinu - 2 * (1 - cosu / 2) * sinu * cosv;
    } else {
      x = 3 * cosu * (1 + sinu) + 2 * (1 - cosu / 2) * ((cosv * -1.0));
      z = -8 * sinu;
    }
    y = -2 * (1 - cosu / 2) * sinv;
    return [x / 6, z / 6, y / 6];
  };
};

var MoebiusLikeStrip = function(maj, a, b) {
  "use strict";
  this.maj = typeof maj === "undefined" || maj === null ? 1.25 : maj;
  this.a = typeof a === "undefined" || a === null ? 0.125 : a;
  this.b = typeof b === "undefined" || b === null ? 0.5 : b;
  this.endPoints = function() {
    return [0, Math.PI, 0, H3DU.Math.PiTimes2];
  };
  this.evaluate = function(u, v) {
    var x, y, z;
    var cosu = Math.cos(u);
    var sinu = u >= 0 && u < 6.283185307179586 ? u <= 3.141592653589793 ? Math.sqrt(1.0 - cosu * cosu) : -Math.sqrt(1.0 - cosu * cosu) : Math.sin(u);
    var cosv = Math.cos(v);
    var sinv = v >= 0 && v < 6.283185307179586 ? v <= 3.141592653589793 ? Math.sqrt(1.0 - cosv * cosv) : -Math.sqrt(1.0 - cosv * cosv) : Math.sin(v);
    x = this.a * cosv * cosu - this.b * sinv * sinu;
    z = this.a * cosv * sinu + this.b * sinv * cosu;
    // Find the sine and cosine of u + u
    var cosu2 = cosu * cosu - sinu * sinu;
    var sinu2 = sinu * cosu * 2;
    y = (this.maj + x) * sinu2;
    x = (this.maj + x) * cosu2;
    return [x, z, y];
  };
};

var MoebiusStrip = function(radius, width) {
  "use strict";
  this.radius = typeof radius === "undefined" || radius === null ? 1 : radius;
  this.width = typeof width === "undefined" || width === null ? 0.5 : width;
  this.endPoints = function() {
    return [-this.width, this.width, 0, H3DU.Math.PiTimes2];
  };
  this.evaluate = function(u, v) {
    var x, y, z;
    var halfv = v / 2;
    var cosv2 = Math.cos(halfv);
    var sinv2 = halfv >= 0 && halfv < 6.283185307179586 ? halfv <= 3.141592653589793 ? Math.sqrt(1.0 - cosv2 * cosv2) : -Math.sqrt(1.0 - cosv2 * cosv2) : Math.sin(halfv);
    var cosv = cosv2 * cosv2 - sinv2 * sinv2;
    var sinv = 2 * sinv2 * cosv2;
    var tmp = u * cosv2 + this.radius;
    x = cosv * tmp;
    y = sinv * tmp;
    z = sinv2 * u;
    return [x, y, z];
  };
};

var shapeGroup = new H3DU.ShapeGroup();

var link0 = null;
var allsettings = {};

addLink("Superellipsoid", link0 = function() {
  "use strict";
  pushSettings(allsettings, shapeGroup, function(allsettings) {
    var surf = new Superellipsoid(
      allsettings["superel-x"],
      allsettings["superel-y"],
      allsettings["superel-z"],
      allsettings["superel-n"],
      allsettings["superel-m"]
    );
    return makeMesh(surf);
  }, {
    "superel-x":["X radius", 1.2, 0.05, 2.0, 0.05],
    "superel-y":["Y radius", 1, 0.05, 2.0, 0.05],
    "superel-z":["Z radius", 1, 0.05, 2.0, 0.05],
    "superel-n":["N", 1, 0.05, 3.0, 0.05],
    "superel-m":["M", 1, 0.05, 3.0, 0.05]
  });
});

addLink("Klein bottle", function() {
  "use strict";
  pushSettings(allsettings, shapeGroup, function() {
    return makeMesh(
   new KleinBottle());
  }, {});
});
addLink("Surface of revolution for f(x) = sin x", function() {
  "use strict";
  pushSettings(allsettings, shapeGroup, function() {
    return makeMesh(H3DU.SurfaceOfRevolution.fromFunction(function(x) {
      return Math.sin(x);
    }, -Math.PI, Math.PI, [1, 0, 0]));
  }, {});
});
addLink("Surface of revolution for f(x) = x<sup>2</sup>", function() {
  "use strict";
  pushSettings(allsettings, shapeGroup, function() {
    return makeMesh(H3DU.SurfaceOfRevolution.fromFunction(function(x) {
      return x * x;
    }, -1, 1, [1, 0, 0]));
  }, {});
});
addLink("...for f(x) = x<sup>2</sup>+0.01", function() {
  "use strict";
  pushSettings(allsettings, shapeGroup, function() {
    return makeMesh(H3DU.SurfaceOfRevolution.fromFunction(function(x) {
      return x * x + 0.01;
    }, -1, 1, [1, 0, 0]));
  }, {});
});
addLink("Cylinder", function() {
  "use strict";
  pushSettings(allsettings, shapeGroup, function() {
    return makeMesh(H3DU.SurfaceOfRevolution.fromFunction(function() {
      return 1;
    }, -1, 1, [0, 1, 0]));
  }, {});
});
addLink("Cone", function() {
  "use strict";
  pushSettings(allsettings, shapeGroup, function() {
    return makeMesh(H3DU.SurfaceOfRevolution.fromFunction(function(x) {
      x += -1;
      return x / 2;
    }, -1, 1, [0, 1, 0]));
  }, {});
});
addLink("Torus as Surface of Revolution", function() {
  "use strict";
  pushSettings(allsettings, shapeGroup, function() {
    return makeMesh(H3DU.SurfaceOfRevolution.torus(1, 0.125));
  }, {});
});
addLink("M&ouml;bius-like strip", function() {
  "use strict";
  pushSettings(allsettings, shapeGroup, function(allsettings) {
    return makeMesh(
    new MoebiusLikeStrip(
      allsettings["moeb-maj"],
      allsettings["moeb-a"],
      allsettings["moeb-b"]
    ));
  }, {
    "moeb-maj":["Size", 1.25, 0.05, 3.0, 0.05],
    "moeb-a":["Height", 0.125, 0.05, 2.0, 0.05],
    "moeb-b":["Thickness", 0.05, 0.05, 1.0, 0.05]
  });
});

addLink("Supertoroid", function() {
  "use strict";
  pushSettings(allsettings, shapeGroup, function(allsettings) {
    return makeMesh(
    new Supertoroid(
      allsettings["superto-x"],
      allsettings["superto-y"],
      allsettings["superto-ir"],
      allsettings["superto-n"],
      allsettings["superto-m"]
    ));
  }, {
    "superto-x":["X radius", 1, 0.05, 2.0, 0.05],
    "superto-y":["Y radius", 1, 0.05, 2.0, 0.05],
    "superto-ir":["Inner radius", 0.25, 0.05, 1.0, 0.05],
    "superto-n":["N", 1, 0.05, 3.0, 0.05],
    "superto-m":["M", 1, 0.05, 3.0, 0.05]
  });
});

addLink("M&ouml;bius strip", function() {
  "use strict";
  pushSettings(allsettings, shapeGroup, function(allsettings) {
    return makeMesh(
    new MoebiusStrip(
      allsettings["moeb2-r"],
      allsettings["moeb2-w"]
    ));
  }, {
    "moeb2-r":["Radius", 1, 0.05, 2, 0.05],
    "moeb2-w":["Width", 0.25, 0.05, 2, 0.05]
  });
});

var bsplineSurf = null;
addLink("B-Spline Surface", function() {
  "use strict";
  pushSettings(allsettings, shapeGroup, function() {
    var bspline = [];
    for(var i = 0; i <= 5; i++) {
      var c = [];
      for(var j = 0; j <= 5; j++) {
        var cp = [
          j * 5.0 / 5 - 2.5,
          i * 5.0 / 5 - 2.5,
          Math.random() * 2.5 - 1.25
        ];
        c.push(cp);
      }
      bspline.push(c);
    }
    if(!bsplineSurf)
      bsplineSurf = H3DU.BSplineSurface.clamped(bspline, 3, 3);
    return makeMesh(bsplineSurf);
  }, {});
});

// Create the 3D scene; find the HTML canvas and pass it
  // to Scene3D.
var scene = new H3DU.Scene3D(document.getElementById("canvas"));
var input = new H3DU.InputTracker(scene.getCanvas());
scene.setClearColor("white");
var sub = new H3DU.Batch3D();
var camera = new H3DU.Camera(sub, 45, 1, 100);
camera.setDistance(5);
var pc = new H3DU.FrameCounterDiv();
link0();
sub.addShape(shapeGroup);
H3DU.renderLoop(function() {
  "use strict";
  pc.update();
  camera.update(input.update());
  sub.getLights().setDirectionalLight(0, camera.getPosition());
  scene.render(sub);
});
// -->
</script>
</body>
